package com.wlf.admin.system.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.wlf.admin.common.dto.CacheKey;
import com.wlf.admin.common.util.AjaxBean;
import com.wlf.admin.system.domain.RoleMenu;
import com.wlf.admin.system.domain.RoleUser;
import com.wlf.admin.system.domain.SysMenu;
import com.wlf.admin.system.mapper.SysMenuMapper;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@CacheConfig(cacheNames = CacheKey.menu)
public class SysMenuService extends ServiceImpl<SysMenuMapper, SysMenu> {


    public AjaxBean getList(SysMenu menu) {
        List<SysMenu> list = this.lambdaQuery()
                .like(StrUtil.isNotBlank(menu.getName()), SysMenu::getName, menu.getName())
                .like(StrUtil.isNotBlank(menu.getUrl()), SysMenu::getUrl, menu.getUrl())
                .list();
        ArrayList<SysMenu> parentMenu = new ArrayList<>();
        list.forEach(i -> reverseOrgan(i, parentMenu));
        list.addAll(parentMenu);
        List<Tree<Long>> treeMenu = TreeUtil.build(list, 0L,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getPid());
                    tree.setWeight(treeNode.getSort());
                    tree.setName(treeNode.getName());
                    tree.putExtra("menuIcon", treeNode.getMenuIcon());
                    tree.putExtra("url", treeNode.getUrl());
                    tree.putExtra("type", treeNode.getType());
                    tree.putExtra("auth", treeNode.getAuth());
                    tree.putExtra("sort", treeNode.getSort());
                    tree.putExtra("remark", treeNode.getRemark());
                });
        return AjaxBean.getOkData(treeMenu).setCount((long) list.size()).setCode(0);
    }

    @Cacheable(key = "#id")
    public SysMenu get(Long id) {
        return this.getById(id);
    }

    /**
     * 功能描述: 向上递归直到根节点
     *
     * @author wlf 2023/9/5 10:14
     */
    private void reverseOrgan(SysMenu organ, List<SysMenu> organs) {
        organs.add(organ);
        SysMenu pOrgan = SpringUtil.getBean(this.getClass()).get(organ.getPid());
        if (pOrgan != null) {
            reverseOrgan(pOrgan, organs);
        }
    }

    /**
     * 删除菜单
     */
    @Caching(
            evict = {
                    @CacheEvict(key = "#id"),
                    @CacheEvict(cacheNames = CacheKey.power, allEntries = true)
            }
    )
    public AjaxBean del(Long id) {
        // 判断是否有子集，有的话禁止删除
        if (this.lambdaQuery().eq(SysMenu::getPid, id).count() > 0) {
            return AjaxBean.getError("菜单存在子集无法删除!");
        }
        return AjaxBean.getByBool(this.removeById(id));
    }


    public AjaxBean add(SysMenu menu) {
        this.save(menu);
        return AjaxBean.getOkData(menu);
    }


    @Caching(
            evict = {
                    @CacheEvict(key = "#menu.id"),
                    @CacheEvict(cacheNames = CacheKey.power, allEntries = true)
            }
    )
    public AjaxBean update(SysMenu menu) {
        return AjaxBean.getByBool(this.updateById(menu));
    }

    /**
     * 获取菜单树
     */
    public List<Tree<Long>> menuTree() {
        TreeNodeConfig tConfig = new TreeNodeConfig();
        // 自定义属性名 都要默认值的
        tConfig.setIdKey("id");
        tConfig.setChildrenKey("children");
        tConfig.setNameKey("title");
        return TreeUtil.build(this.list(), 0L, tConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getPid());
                    tree.setWeight(treeNode.getSort());
                    tree.setName(treeNode.getName());
                    tree.putExtra("spread", true);
                });
    }

    /**
     * 功能描述: 权限缓存
     *
     * @author wlf 2023/8/24 10:51
     */
    @Cacheable(cacheNames = CacheKey.power, key = "#userId")
    public List<SysMenu> getMenuListByUserId(Long userId) {
        //有小可爱喜欢乱玩，超级管理员不受权限管理，默认全部菜单
        if (userId.intValue() == 1) {
            return this.lambdaQuery().list();
        } else {
            List<Long> menuIds = Db.lambdaQuery(RoleMenu.class)
                    .in(RoleMenu::getRoleId, Db.lambdaQuery(RoleUser.class).eq(RoleUser::getUserId, userId)
                            .list().stream().map(RoleUser::getRoleId).collect(Collectors.toList()))
                    .list().stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
            if(menuIds.isEmpty()){
                throw new RuntimeException("当前用户没有分配任何权限，无法访问");
            }
            return this.lambdaQuery().in(SysMenu::getId, CollectionUtil.newHashSet(menuIds)).list();
        }

    }
}
